use std::io::Cursor;

use anyhow::Ok;
use chrono::Local;
use crypto::digest::Digest;
use crypto::md5::Md5;
use crypto::sha1::Sha1;
use crypto::sha2::Sha256;
use headers::HeaderMap;
use image::io::Reader as ImageReader;
use image::{
    imageops, DynamicImage, FlatSamples, GenericImage, GenericImageView, ImageBuffer, Pixel,
    Primitive, Rgba,
};
use lettre::{
    message::header::ContentType, transport::smtp::authentication::Credentials, Message,
    SmtpTransport, Transport,
};
use rand::distributions::{Alphanumeric, DistString};
use rand::Rng;
use serde_json::json;

use crate::settings::EmailConfig;
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789)(*&^%$#@!~";
const CHARSET2: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const CHARSET3: &[u8] = b"0123456789";
const SESSION_ID_COOKIE_NAME: &str = "axum_rs_session_id";

// 获取给定长度的随机字符串
pub fn get_rand_pwd(n: usize) -> String {
    let mut rng = rand::thread_rng();
    let str = (0..n)
        .map(|_| {
            let idx = rng.gen_range(0..CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();
    str
}

// 获取给定长度的随机字符串
pub fn get_rand_str2(n: usize) -> String {
    let mut rng = rand::thread_rng();
    let str = (0..n)
        .map(|_| {
            let idx = rng.gen_range(0..CHARSET2.len());
            CHARSET2[idx] as char
        })
        .collect();
    str
}
// 获取给定长度的随机数字
pub fn get_rand_num(n: usize) -> String {
    let mut rng = rand::thread_rng();
    let str = (0..n)
        .map(|_| {
            let idx = rng.gen_range(0..CHARSET3.len());
            CHARSET3[idx] as char
        })
        .collect();
    str
}
// 随机字符串
pub fn get_rand_str(len: usize) -> String {
    let str = Alphanumeric.sample_string(&mut rand::thread_rng(), len);
    str
}

// sha1
pub fn sha1(str: &str) -> String {
    let mut hasher = Sha1::new();
    hasher.input_str(str);
    hasher.result_str()
}
// sha256
pub fn sha256(str: &str) -> String {
    let mut hasher = Sha256::new();
    hasher.input_str(str);
    hasher.result_str()
}
// md5 32bit
pub fn md532(str: &str) -> String {
    let mut hasher = Md5::new();
    hasher.input_str(str);
    hasher.result_str()
}
// md5 16bit
pub fn md516(str: &str) -> String {
    let data = md532(str);
    let result = &data[8..24];
    result.to_string()
}
// 获取时间戳
pub fn get_timestamp() -> i64 {
    let now = Local::now().timestamp();
    now
}

// 获取毫秒时间戳
pub fn get_milli_timestamp() -> i64 {
    let now = Local::now().timestamp_millis();
    now
}

// 获取当前时间，格式YYYY-MM-DD HH:MM:ss
pub fn get_currdate() -> String {
    let now = Local::now().format("%Y-%m-%d %H:%M:%S");
    now.to_string()
}

// 发送企业微信机器人通知
pub async fn send_mp_notify(url: &str, content: String) -> anyhow::Result<()> {
    let client = reqwest::Client::new();

    let json_content = json!({
            "msgtype":"text",
            "text":{
                "content":&content,
            },
    });

    let _res = client
        .post(url)
        .body(json_content.to_string())
        .send()
        .await?;
    Ok(())
}
// markdown通知
pub async fn send_mp_md_notify(url: &str, content: String) -> anyhow::Result<()> {
    let client = reqwest::Client::new();

    let json_content = json!({
            "msgtype":"markdown",
            "markdown":{
                "content":&content,
            },
    });

    let _res = client
        .post(url)
        .body(json_content.to_string())
        .send()
        .await?;
    Ok(())
}

/// 将 Session ID 保存到 Cookie
pub fn save_session_id_to_cookie(session_id: &str, headers: &mut HeaderMap) {
    let cookie = format!("{}={}", SESSION_ID_COOKIE_NAME, session_id);
    headers.insert(
        axum::http::header::SET_COOKIE,
        cookie.as_str().parse().unwrap(),
    );
}

/// 从 cookie 中获取session id
pub fn get_session_from_cookie(headers: &HeaderMap) -> Option<String> {
    let cookies = headers
        .get(axum::http::header::COOKIE)
        .and_then(|value| value.to_str().ok())
        .unwrap_or("");
    if cookies.is_empty() {
        return None;
    }
    let mut session_id: Option<String> = None;
    let cookies: Vec<&str> = cookies.split(';').collect();
    for cookie in cookies {
        let cookie_pair: Vec<&str> = cookie.split('=').collect();
        let cookie_name = cookie_pair[0].trim();
        let cookie_value = cookie_pair[1].trim();
        if cookie_name == SESSION_ID_COOKIE_NAME && !cookie_value.is_empty() {
            session_id = Some(cookie_value.to_string());
            break;
        }
    }
    session_id
}

pub fn draw_mp_image(qrcode: Vec<u8>, icode: String, oimg: &String) -> anyhow::Result<()> {
    let bg_img = image::open("images/codetmpl1.png")?;
    let qr_img = image::load_from_memory(&qrcode)?;
    let mut imgbuf = image::ImageBuffer::new(900, 500);
    imgbuf.copy_from(&bg_img, 0, 0)?;
    imgbuf.copy_from(&qr_img, 35, 35)?;
    let icode_chars: Vec<String> = icode
        .chars()
        .map(|c| format!("images/r{}.jpg", c))
        .collect();
    let mut imgs: Vec<image::DynamicImage> = Vec::new();
    for i in icode_chars {
        let j = image::open(i)?;
        imgs.push(j);
    }
    let num_img = h_concat(&imgs);
    imgbuf.copy_from(&num_img, 480, 227)?;
    imgbuf.save(oimg)?;
    Ok(())
}

pub fn draw_number_image(icode: String) -> anyhow::Result<()> {
    let icode_chars: Vec<String> = icode.chars().map(|c| format!("images/{}.jpg", c)).collect();
    println!("the icode_chars {:?}", icode_chars);
    let mut imgs: Vec<image::DynamicImage> = Vec::new();
    for i in icode_chars {
        let j = image::open(i)?.resize(50, 200, imageops::FilterType::Triangle);
        imgs.push(j);
    }
    // let img1 = h_concat(&imgs);

    h_concat(&imgs).save("tmp/test1.jpg").unwrap();
    Ok(())
}
// resize 图片 数字图片宽50px，高67px
pub fn resize_number_image(num: i32) -> anyhow::Result<()> {
    let img = format!("images/{}.jpg", num);
    let dimg = image::open(img)?.resize(50, 200, imageops::FilterType::Lanczos3);

    println!("img w:{},h:{}", dimg.dimensions().0, dimg.dimensions().1);
    let oimg = format!("images/r{}.jpg", num);
    dimg.save(&oimg).unwrap();
    Ok(())
}

fn h_concat<I, P, S>(images: &[I]) -> ImageBuffer<P, Vec<S>>
where
    I: GenericImageView<Pixel = P>,
    P: Pixel<Subpixel = S> + 'static,
    S: Primitive + 'static,
{
    // The final width is the sum of all images width.
    let img_width_out: u32 = images.iter().map(|im| im.width()).sum();

    // The final height is the maximum height from the input images.
    let img_height_out: u32 = images.iter().map(|im| im.height()).max().unwrap_or(0);
    // Initialize an image buffer with the appropriate size.
    let mut imgbuf = image::ImageBuffer::new(img_width_out, img_height_out);
    let mut accumulated_width = 0;

    // Copy each input image at the correct location in the output image.
    for img in images {
        imgbuf.copy_from(img, accumulated_width, 0).unwrap();
        accumulated_width += img.width();
    }

    imgbuf
}
// 仅绘制小程序码
pub fn draw_mp_image_v2(qrcode: Vec<u8>, oimg: &String) -> anyhow::Result<()> {
    // let imgbuf = ImageReader::new(Cursor::new(qrcode)).with_guessed_format()?.decode()?;
    let qr_img = image::load_from_memory(&qrcode)?;
    let mut imgbuf = image::ImageBuffer::new(430, 430);
    imgbuf.copy_from(&qr_img, 0, 0)?;
    imgbuf.save(oimg)?;
    Ok(())
}

// 发送邮件
pub fn send_email(
    conf: &EmailConfig,
    recipient: String,
    subject: String,
    content: String,
) -> anyhow::Result<()> {
    let email = Message::builder()
        .from(conf.user_name.parse().unwrap())
        .reply_to(conf.user_name.parse().unwrap())
        .to(recipient.parse().unwrap())
        .subject(subject)
        .header(ContentType::TEXT_PLAIN)
        .body(content)
        .unwrap();

    let creds = Credentials::new(conf.user_name.clone(), conf.password.clone());

    let mailer = SmtpTransport::relay(&conf.host)
        .unwrap()
        .credentials(creds)
        .build();

    // Send the email
    mailer.send(&email)?;
    Ok(())
}
// 生成核验码的加密字符串
pub fn gen_ecode_str(ecode: &str, ts: i64, shared_key: &str) -> String {
    let str = format!("{}{}{}", ecode, ts, shared_key);
    sha256(&str)
}

// 校验核验码的加密字符串
pub fn check_ecode(ecode: &str, ts: &str, shared_key: &str, sign: &str) -> bool {
    let str = format!("{}{}{}", ecode, ts, shared_key);
    let mstr = sha256(&str);
    if mstr == sign {
        return true;
    }
    false
}

// 校验appsecret是否正确
pub fn check_appsecret(appsecret: &str, sign: &str) -> bool {
    let md5_appsecret = md532(&appsecret);
    md5_appsecret == sign
}
// 生成账号的appid,appsecret
pub fn gen_app_account_id() -> (String, String) {
    let ts = get_milli_timestamp().to_string();
    let md516 = md516(&ts);
    let appid = format!("ic{}", md516);
    let md532 = md532(&appid);
    (appid, md532)
}

// 生成app token
pub fn gen_app_token() -> String {
    let ts = get_milli_timestamp().to_string();
    let token = format!("zz-{}", ts);
    let md532 = md532(&token);
    md532
}
// 重置账号的appsecret
pub fn reset_app_account_secret() -> String {
    let ts = get_milli_timestamp().to_string();
    let md516 = md516(&ts);
    let rstr = format!("ic{}", md516);
    let md532 = md532(&rstr);
    md532
}
